{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# [泛型就这么简单](https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247484109&idx=1&sn=ed48fa9216c260fb9b622d9f383d8c25&chksm=ebd743ccdca0cadad9e8e4a5cd9a7ce96b595ddaf6fb2e817a9a0d49d4d54c50bb93a97e56eb&scene=21###wechat_redirect)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 什么是泛型？\n",
    "**Java泛型设计原则：只要在编译时期没有出现警告，那么运行时期就不会出现ClassCastException异常。**\n",
    "\n",
    "范型：**把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型**\n",
    "\n",
    "参数化类型:\n",
    "- 把类型当作是参数一样传递\n",
    "- `<数据类型>` 只能是引用类型\n",
    "\n",
    "相关术语：\n",
    "- `ArrayList<E>`中的E称为类型参数变量\n",
    "- `ArrayList<Integer>`中的Integer称为实际类型参数\n",
    "- 整个称为`ArrayList<E>`泛型类型\n",
    "- 整个`ArrayList<Integer>`称为参数化的类型ParameterizedType"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 为什么需要泛型\n",
    "**早期Java是使用Object来代表任意类型的，但是向下转型有强转的问题，这样程序就不太安全**\n",
    "\n",
    "首先，我们来试想一下：没有泛型，集合会怎么样\n",
    "\n",
    "Collection、Map集合对元素的类型是没有任何限制的。**本来我的Collection集合装载的是全部的Dog对象，但是外边把Cat对象存储到集合中，是没有任何语法错误的。**\n",
    "\n",
    "把对象扔进集合中，集合是不知道元素的类型是什么的，仅仅知道是Object。因此在get()的时候，返回的是Object。**外边获取该对象，还需要强制转换**\n",
    "\n",
    "有了泛型以后：\n",
    "\n",
    "- 代码更加简洁（不用强制转换）\n",
    "- 程序更加健壮（只要编译时期没有警告，那么运行时期就不会出现ClassCastException异常）\n",
    "- 可读性和稳定性（在编写集合的时候，就限定了类型）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 有了泛型后使用增强for遍历集合\n",
    "在创建集合的时候，明确了集合的类型了，可以使用增强for来遍历集合"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T06:38+0000",
     "start_time": "2020-08-25T06:38:21.921Z"
    }
   },
   "outputs": [],
   "source": [
    "//创建集合对象\n",
    "ArrayList<String> list = new ArrayList();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T06:39+0000",
     "start_time": "2020-08-25T06:39:11.797Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list.add(\"hello\");\n",
    "list.add(\"world\");\n",
    "list.add(\"anlzou\");"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T06:40+0000",
     "start_time": "2020-08-25T06:40:25.541Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello world anlzou "
     ]
    }
   ],
   "source": [
    "//遍历，由于明确了类型，可以增强for\n",
    "for(String s : list){\n",
    "    System.out.print(s+\" \");\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 泛型基础\n",
    "### 泛型类\n",
    "**泛型类就是把泛型定义在类上，用户使用该类的时候，才把类型明确下来…**这样的话，明确了什么类型，该类就代表着什么类型…用户在使用的时候就不用担心强转的问题，运行时转换异常的问题了。\n",
    "- **在类上定义的泛型，在类的方法中也可以使用！**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T07:10+0000",
     "start_time": "2020-08-25T07:10:32.298Z"
    }
   },
   "outputs": [],
   "source": [
    "/*\n",
    "    1:把泛型定义在类上\n",
    "    2:类型变量定义在类上,方法中也可以使用\n",
    " */\n",
    " public class ObjectTool<T>{\n",
    "     private T obj;\n",
    "     \n",
    "     public T getObj(){\n",
    "         return obj;\n",
    "     }\n",
    "     \n",
    "     public void setObj(T obj){\n",
    "         this.obj = obj;\n",
    "     }\n",
    " }"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 测试代码：\n",
    "\n",
    "**想要使用哪种类型，就在创建的时候指定类型。使用的时候，该类就会自动转换成想要使用的类型了**。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T07:17+0000",
     "start_time": "2020-08-25T07:17:49.264Z"
    }
   },
   "outputs": [],
   "source": [
    "public static void main(){\n",
    "    //创建对象并指定元素类型\n",
    "    ObjectTool<String> tool = new ObjectTool();\n",
    "    \n",
    "    tool.setObj(new String(\"anlzou\"));\n",
    "    String s = tool.getObj();\n",
    "    System.out.println(s);\n",
    "    \n",
    "    //创建对象并指定元素类型\n",
    "    ObjectTool<Integer> objectTool = new ObjectTool();\n",
    "    /**\n",
    "    * 如果我在这个对象里传入的是String类型的,它在编译时期就通过不了了.\n",
    "    */\n",
    "    objectTool.setObj(10);\n",
    "    int i = objectTool.getObj();\n",
    "    System.out.println(i);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T07:17+0000",
     "start_time": "2020-08-25T07:17:55.423Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "anlzou\n",
      "10\n"
     ]
    }
   ],
   "source": [
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 泛型方法\n",
    "某一个方法上需要使用泛型….外界仅仅是关心该方法，不关心类其他的属性\n",
    "- 定义泛型方法…**泛型是先定义后使用的**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T07:26+0000",
     "start_time": "2020-08-25T07:26:21.215Z"
    }
   },
   "outputs": [],
   "source": [
    " public class ObjectTool<T>{\n",
    "     private T obj;\n",
    "     \n",
    "     public T getObj(){\n",
    "         return obj;\n",
    "     }\n",
    "     \n",
    "     public void setObj(T obj){\n",
    "         this.obj = obj;\n",
    "     }\n",
    "     \n",
    "     //定义泛型方法\n",
    "    public <T> void show(T t){\n",
    "        System.out.println(t);\n",
    "    }\n",
    " }"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 测试代码：\n",
    "\n",
    "**传递进来的是什么类型，返回值就是什么类型了**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T07:27+0000",
     "start_time": "2020-08-25T07:27:29.806Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "anlzou\n",
      "24\n",
      "24.5\n"
     ]
    }
   ],
   "source": [
    "public static void main(){\n",
    "    ObjectTool tool = new ObjectTool();\n",
    "    \n",
    "    tool.show(\"anlzou\");\n",
    "    tool.show(24);\n",
    "    tool.show(24.5);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 泛型类派生出的子类\n",
    "**泛型类是拥有泛型这个特性的类，它本质上还是一个Java类，那么它就可以被继承**\n",
    "1. 子类明确泛型类的类型参数变量\n",
    "2. 子类不明确泛型类的类型参数变量"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 子类明确泛型类的类型参数变量"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 泛型接口"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T08:01+0000",
     "start_time": "2020-08-25T08:01:43.265Z"
    }
   },
   "outputs": [],
   "source": [
    "public interface Base<T>{\n",
    "    public abstract void show(T t);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 实现泛型接口的类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T07:36+0000",
     "start_time": "2020-08-25T07:36:23.678Z"
    }
   },
   "outputs": [],
   "source": [
    "public class StringImpl implements Base<String>{\n",
    "    @Override\n",
    "    public void show(String s){\n",
    "        System.out.println(s);\n",
    "    }\n",
    "}\n",
    "\n",
    "public class IntegerImpl implements Base<Integer>{\n",
    "    @Override\n",
    "    public void show(Integer i){\n",
    "        System.out.println(i);\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T07:37+0000",
     "start_time": "2020-08-25T07:37:30.450Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "anlzou\n"
     ]
    }
   ],
   "source": [
    "StringImpl stringImpl = new StringImpl();\n",
    "stringImpl.show(\"anlzou\");"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T07:38+0000",
     "start_time": "2020-08-25T07:38:08.352Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "24\n"
     ]
    }
   ],
   "source": [
    "IntegerImpl integerImpl = new IntegerImpl();\n",
    "integerImpl.show(24);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 子类不明确泛型类的类型参数变量\n",
    "当子类不明确泛型类的类型参数变量时，**外界使用子类的时候，也需要传递类型参数变量进来，在实现类上需要定义出类型参数变量**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T08:01+0000",
     "start_time": "2020-08-25T08:01:50.103Z"
    }
   },
   "outputs": [],
   "source": [
    "public class InterImpl<T> implements Base<T>{\n",
    "    @Override\n",
    "    public void show(T t){\n",
    "        System.out.println(t);\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T08:04+0000",
     "start_time": "2020-08-25T08:04:56.384Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "100\n"
     ]
    }
   ],
   "source": [
    "// Test，习惯了写函数，jupyter中可以不写函数，只写代码片段\n",
    "public static void main(){\n",
    "    //Base<String> s = new InterImpl<>();等价\n",
    "    Base<String> s = new InterImpl();\n",
    "    s.show(\"100\");\n",
    "}\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 类型通配符\n",
    "`？`号通配符表示可以匹配任意类型，任意的Java类都可以匹配"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T08:16+0000",
     "start_time": "2020-08-25T08:16:27.192Z"
    }
   },
   "source": [
    "#### 通配符上限\n",
    "```java\n",
    "//接收一个List集合，它只能操作数字类型的元素（Float、Integer、Doubl、Byte等数字类型）\n",
    "List<? extends Number>  //List集合装载的元素只能是Number的子类或自身\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T08:24+0000",
     "start_time": "2020-08-25T08:24:44.261Z"
    }
   },
   "outputs": [],
   "source": [
    "public static void main(){\n",
    "    //List集合装载的是Integer,可以调用该方法\n",
    "    List<Integer> integer = new ArrayList<>();\n",
    "    test(integer);\n",
    "    \n",
    "    /**\n",
    "    *List集合装载的是String,在编译时期就报错了\n",
    "    *List<String> strings = new ArrayList();这样不报错！！！\n",
    "    */\n",
    "    //List<String> strings = new ArrayList<>();\n",
    "    //test(strings);\n",
    "}\n",
    "\n",
    "public static void test(List<? extends Number> list){\n",
    "    \n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 通配符下限\n",
    "```java\n",
    "//传递进来的只能是ObjectType或ObjectType的父类\n",
    "<? super ObjectType>\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T08:30+0000",
     "start_time": "2020-08-25T08:30:23.792Z"
    }
   },
   "outputs": [
    {
     "ename": "CompilationException",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30mpublic TreeSet(Comparator<\u001b[0m\u001b[1m\u001b[30m\u001b[41m\u001b[0m\u001b[1m\u001b[30m? super E>comparator){\u001b[0m",
      "\u001b[1m\u001b[31millegal start of expression\u001b[0m",
      "",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30mpublic TreeSet(Comparator<? super\u001b[0m\u001b[1m\u001b[30m\u001b[41m\u001b[0m\u001b[1m\u001b[30m E>comparator){\u001b[0m",
      "\u001b[1m\u001b[31m'.' expected\u001b[0m",
      "",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30mpublic TreeSet(Comparator<? super E>comparator\u001b[0m\u001b[1m\u001b[30m\u001b[41m\u001b[0m\u001b[1m\u001b[30m){\u001b[0m",
      "\u001b[1m\u001b[31m: expected\u001b[0m",
      ""
     ]
    }
   ],
   "source": [
    "public TreeSet(Comparator<? super E>comparator){\n",
    "    this(new TreeMap<>(comparator));\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 通配符和泛型方法\n",
    "大多时候，我们都可以使用泛型方法来代替通配符的\n",
    "```java\n",
    "//使用通配符\n",
    "public static void test(List<?> list){\n",
    "\n",
    "}\n",
    "\n",
    "//使用泛型方法\n",
    "public <T> void test2(Test<T> t){\n",
    "\n",
    "}\n",
    "```\n",
    "原则：\n",
    "\n",
    "- 如果`参数之间的类型有依赖关系`，或者`返回值是与参数之间有依赖关系`的。那么就使用泛型方法。\n",
    "- 如果`没有依赖关系`的，就使用通配符，通配符会`灵活一些`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 泛型擦除\n",
    "泛型是**提供给javac编译器使用的**，它用于限定集合的输入类型，让编译器在源代码级别上，即挡住向集合中插入非法数据。但编译器编译完带有泛形的java程序后，**生成的class文件中将不再带有泛形信息**，以此使程序运行效率不受到影响，这个过程称之为“擦除”。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 兼容性\n",
    "JDK5提出了泛型这个概念，但是JDK5以前是没有泛型的。也就是泛型是需要兼容JDK5以下的集合的。\n",
    "\n",
    "**当把带有泛型特性的集合赋值给老版本的集合时候，会把泛型给擦除了。**\n",
    "\n",
    "值得注意的是：**它保留的就类型参数的上限。**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T08:48+0000",
     "start_time": "2020-08-25T08:48:52.565Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "true\n"
     ]
    }
   ],
   "source": [
    "List<String> list = new ArrayList<>();\n",
    "\n",
    "//类型被擦除了，保留的是类型的上限，String的上限就是Object\n",
    "List listNew = list;\n",
    "\n",
    "System.out.println(listNew instanceof Object);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果我**把没有类型参数的集合赋值给带有类型参数的集合赋值**，这又会怎么样？？\n",
    "\n",
    "它也不会报错，仅仅是提示“未经检查的转换”"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T08:53+0000",
     "start_time": "2020-08-25T08:53:01.213Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "true\n"
     ]
    }
   ],
   "source": [
    "List list = new ArrayList();\n",
    "List<String> listNew = list;\n",
    "\n",
    "System.out.println(listNew instanceof Object);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 泛型的应用\n",
    "当我们写网页的时候，常常会有多个DAO，我们要写每次都要写好几个DAO，这样会有点麻烦。\n",
    "\n",
    "**只写一个抽象DAO，别的DAO只要继承该抽象DAO，就有对应的方法了。**\n",
    "\n",
    "**要实现这样的效果，肯定是要用到泛型的。因为在抽象DAO中，是不可能知道哪一个DAO会继承它自己，所以是不知道其具体的类型的。而泛型就是在创建的时候才指定其具体的类型。**\n",
    "\n",
    "- 抽象Dao"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T09:15+0000",
     "start_time": "2020-08-25T09:15:52.812Z"
    }
   },
   "outputs": [
    {
     "ename": "CompilationException",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30mpublic abstract class BaseDao<T>{\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    //模拟hibernate\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    private Session session;\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    private Class classSon;\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    \u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    //哪个子类调的这个方法，得到的class就是子类的处理的类型（非常重要）\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    public BaseDao(){\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m        Class classSon = this.getClass();//拿到子类\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m        ParameterizedType pt = (ParameterizedType) classSon.getGenericSuperclass();//BaseDao<Category>\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m        classSon = (Class) pt.getActualTypeArguments()[0];\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m        System.out.println(classSon);\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    }\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    \u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    public void add(T t){\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m        session.save(t);\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    }\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    \u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    public T find(String id){\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m        return (T) session.get(classSon, id);\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    }\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    \u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    public void update(T t){\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m        session.update(t);\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    }\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    \u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    public void delete(String id){\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m        T t = (T) session.get(classSon, id);\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m        session.delete(t);\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    }\u001b[0m",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m}\u001b[0m",
      "\u001b[1m\u001b[31mUnresolved dependencies:\u001b[0m",
      "\u001b[1m\u001b[31m   - class Session\u001b[0m",
      "\u001b[1m\u001b[31m   - class ParameterizedType\u001b[0m"
     ]
    }
   ],
   "source": [
    "public abstract class BaseDao<T>{\n",
    "    //模拟hibernate\n",
    "    private Session session;\n",
    "    private Class classSon;\n",
    "    \n",
    "    //哪个子类调的这个方法，得到的class就是子类的处理的类型（非常重要）\n",
    "    public BaseDao(){\n",
    "        Class classSon = this.getClass();//拿到子类\n",
    "        ParameterizedType pt = (ParameterizedType) classSon.getGenericSuperclass();//BaseDao<Category>\n",
    "        classSon = (Class) pt.getActualTypeArguments()[0];\n",
    "        System.out.println(classSon);\n",
    "    }\n",
    "    \n",
    "    public void add(T t){\n",
    "        session.save(t);\n",
    "    }\n",
    "    \n",
    "    public T find(String id){\n",
    "        return (T) session.get(classSon, id);\n",
    "    }\n",
    "    \n",
    "    public void update(T t){\n",
    "        session.update(t);\n",
    "    }\n",
    "    \n",
    "    public void delete(String id){\n",
    "        T t = (T) session.get(classSon, id);\n",
    "        session.delete(t);\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T09:26+0000",
     "start_time": "2020-08-25T09:26:24.678Z"
    }
   },
   "outputs": [
    {
     "ename": "CompilationException",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30mpublic class Category\u001b[0m\u001b[1m\u001b[30m\u001b[41m\u001b[0m\u001b[1m\u001b[30m Dao extends Base Dao<Category>{\u001b[0m",
      "\u001b[1m\u001b[31m'{' expected\u001b[0m",
      "",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30mpublic class Category Dao extends Base Dao<Category>\u001b[0m\u001b[1m\u001b[30m\u001b[41m\u001b[0m\u001b[1m\u001b[30m{\u001b[0m",
      "\u001b[1m\u001b[31millegal start of type\u001b[0m",
      "",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m}\u001b[0m\u001b[1m\u001b[30m\u001b[41m\u001b[0m\u001b[1m\u001b[30m\u001b[0m",
      "\u001b[1m\u001b[31mreached end of file while parsing\u001b[0m",
      ""
     ]
    }
   ],
   "source": [
    "//实现泛型接口,CategoryDao\n",
    "public class Category Dao extends Base Dao<Category>{\n",
    "\n",
    "}\n",
    "\n",
    "//BookDao\n",
    "public class BookDao extends BaseDao<Book>{\n",
    "\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Java",
   "language": "java",
   "name": "java"
  },
  "language_info": {
   "codemirror_mode": "java",
   "file_extension": ".jshell",
   "mimetype": "text/x-java-source",
   "name": "Java",
   "pygments_lexer": "java",
   "version": "11.0.8+10-post-Ubuntu-0ubuntu120.04"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
